/**
 * 
 */
package twitter;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;

/**
 * @author Fernando
 *
 */
public class KMeansClustering extends Clusterizador{
	
	private static final int NUM_ITER = 100000;
	
	private int numeroK;
	private ArrayList<TwittProcesado> listaTweets;
	private ArrayList<Set<TwittProcesado>> clusters;
	private ArrayList<double[]> centroides;
	private ArrayList<double[]> centroidesAux;

	
	
	public KMeansClustering(int seeds, ArrayList<TwittProcesado> todosTweets){
		numeroK = seeds;
		listaTweets = todosTweets;
		centroides = new ArrayList<double[]>();
		clusters = new ArrayList<Set<TwittProcesado>>();
		centroidesAux = new ArrayList<double[]>();

		for (int i=0; i<seeds; i++){
			clusters.add(new HashSet<TwittProcesado>());
		}
	}
	
	public void ejecutar(){
		//selecionar k-random seeds
		Set<TwittProcesado> seedTweets = new HashSet<TwittProcesado>();
		int i=0;
		
		//Escogemos aleatoriamente K vectores como semillas
		//int vueltas = 0;
		while (i<numeroK){
			
			int semillaAzar = new Random().nextInt(listaTweets.size());
			TwittProcesado nuevaSemilla = listaTweets.get(semillaAzar);
			if (!seedTweets.contains(nuevaSemilla)){	
				if(seedTweets.size() == 0){
				  seedTweets.add(nuevaSemilla);
				  i++;
				}else{
				  double distanciaNuevaSemilla;	
				  boolean semillabuena = true;
				  for (TwittProcesado twittProcesado : seedTweets) {
					  distanciaNuevaSemilla = calcularDistancia(nuevaSemilla, twittProcesado.getVectorIdf());
					  if(distanciaNuevaSemilla <= 0.6)
						  semillabuena = false;
				  }
				  if(semillabuena){
					  seedTweets.add(nuevaSemilla);
					  i++;
				  }
				}  
			}
			//vueltas++;
		}
		
		for (TwittProcesado twittProcesado : seedTweets) {
			System.out.println("Semilla: " + twittProcesado.getTweet());
		}
		
		ArrayList<ArrayList<double[]>> clustersIdf;
		
		//inicializamos los centroides
		for (TwittProcesado twittProcesado : seedTweets) {
			centroides.add(twittProcesado.getVectorIdf());
			centroidesAux.add(twittProcesado.getVectorIdf());
			twittProcesado.setDistanciaAlCentroide(0.0);
			twittProcesado.setNumeroCluster(centroides.indexOf(twittProcesado.getVectorIdf()));
		}
		
		
		int vueltasReales = 0;
		boolean itera = true;
		
		//Iteramos el algoritmo K-Means NUM_ITER veces
		while(itera && vueltasReales<NUM_ITER){
			
			//buscamos la menor distancia de todos los vectores con cada centroide y los asociamos
			for (i=0; i<centroides.size(); i++) {
				double[] centroideActual = centroides.get(i);
				for (TwittProcesado tweet : listaTweets) {
					double distancia = /*Math.abs(*/calcularDistancia(tweet, centroideActual)/*)*/;
					if (tweet.getDistanciaAlCentroide()>distancia){
						tweet.setNumeroCluster(i);
						tweet.setDistanciaAlCentroide(distancia);
					}
				}
			} 
			
			//Agrupamos los vectores idf en sus respectivos cluster de esta iteracion para calcular sus centroides
			clustersIdf = new ArrayList<ArrayList<double[]>>();
			for (i=0; i<numeroK; i++){
				clustersIdf.add(new ArrayList<double[]>());
			}
			for (i=0; i<listaTweets.size(); i++) {
				//clusters = new ArrayList<Set<String>>;
				clustersIdf.get(listaTweets.get(i).getNumeroCluster()).add(listaTweets.get(i).getVectorIdf());
			}
			
			for(i=0;i<centroides.size();i++){
				centroidesAux.set(i, centroides.get(i));
			}
			
			//calculamos los nuevos centroides
			for (i=0; i<centroides.size(); i++){
				centroides.set(i, calcularCentroide(clustersIdf.get(i)));
			}
			vueltasReales++;
			itera = compruebaCambioCentroides(centroides,centroidesAux);
		}
		System.out.println("HA DADO "+vueltasReales+" VUELTAS*******************");
		for (TwittProcesado tweet : listaTweets) {
			int numCluster = tweet.getNumeroCluster();
			clusters.get(numCluster).add(tweet);
		}
		//Mostramos por pantalla lo tweets agrupados
		imprimirClusters();
	}

	private boolean compruebaCambioCentroides(ArrayList<double[]> centroides,ArrayList<double[]> centroidesAux){
		boolean itera = false;
		for(int i=0;i<centroides.size();i++){
			if(esDistinto(centroides.get(i),centroidesAux.get(i))){
				itera = true;
				break;
			}	
		}
		return itera;
		
	}
	
	private boolean esDistinto(double[] ds, double[] ds2) {
		boolean distinto=true;
		for (int i = 0; i < ds2.length; i++) {
			if (ds[i]!=ds2[i])
				return distinto;
		}
		return false;
	}

	private void imprimirClusters() {
		cjtoFinalClusters = new HashSet<Set<String>>();
		for (int i = 0; i < clusters.size(); i++) {
			Set<String> cjtoTwitts = new HashSet<String>(); 
			System.out.println("//------------ Cluster numero " + i + " ------------//");
			for (TwittProcesado tweet : clusters.get(i)) {
				System.out.println(tweet.getTweet());
				cjtoTwitts.add(tweet.getTweet());
			}
			System.out.println();
			cjtoFinalClusters.add(cjtoTwitts);
		}
	}
	
	

}
